home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’93 / Smooth Updates / source / smupdate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-17  |  7.3 KB  |  282 lines  |  [TEXT/KAHL]

  1. /*
  2.  * smupdate.c
  3.  * 14 June 1993 by Mark C Smith • University of Michigan
  4.  * Copyright (c) 1993 Mark C Smith
  5.  *
  6.  * uses "Essential Hack" code & methods to patch BeginUpdate and EndUpdate
  7.  */
  8. #include <QuickDraw.h>
  9. #include <QDOffScreen.h>
  10. #include <Windows.h>
  11. #include <ToolUtils.h>
  12. #include <GestaltEqu.h>
  13. #include <Traps.h>
  14. #include "Useful.h"
  15. #include "smupdate.h"
  16.  
  17. static Boolean        besmooth;
  18. static GWorldPtr    gwp = NULL;
  19. static PixMapHandle    savepmh;
  20. static BitMap        savebm;
  21. static Boolean        inited = false;
  22. static StringHandle    desktopsh;
  23.  
  24. typedef pascal void BEUpdateRoutine( WindowPtr wp );
  25.  
  26.  
  27. /*
  28.  * prototypes for our routines
  29.  */
  30. pascal short SmUpdateGestalt( OSType selector,long *response );
  31. pascal void pBeginUpdate( WindowPtr wp, BEUpdateRoutine *oldBeginUpdateProc );
  32. pascal void pEndUpdate( WindowPtr wp );
  33.  
  34. //
  35. // 14 June 1993 MCS: main was lifted (with appropriate mods) from Essential.c
  36. //
  37. // By convention from the essential hack loader, the init resource begins with the
  38. // four-byte gestalt selector for this hack, and an offset to the gestalt routine
  39. // to be installed on behalf of this hack.  After that is a series of two-word
  40. // entries, where the first word specifies either a trap to be patched or a
  41. // low-memory vector to be patched.  When the first word becomes zero, the traps
  42. // have ended.
  43.  
  44. void main(void) {
  45.     asm {
  46.         dc.l    sSmUpdate    ; our gestalt selector.
  47.         dc.w    SmUpdateGestalt
  48.  
  49.         dc.w    _BeginUpDate
  50.         dc.w    @_NewBeginUpdate
  51.         dc.w    _EndUpDate
  52.         dc.w    @_NewEndUpdate
  53.         dc.w    0
  54.  
  55.     // OK, enough with the header.  here's the patches.  First, BeginUpdate.  We
  56.     // want to tail-patch BeginUpdate, so our patch inserts an extra parameter
  57.     // (the old trap address) so our patch routine can do everything at a high
  58.     // level.  Note that this requires the trap routine (pBeginUpdate) to be
  59.     // declared as a pascal routine, so that it automatically clears away
  60.     // the extra parameter we added.
  61.  
  62. _NewBeginUpdate:
  63.         dc.l    WayBadValue
  64.         move.l    (a7),-(a7)                ; make space for an extra parameter.
  65.         move.l    @_NewBeginUpdate,4(a7)    ; the old address is that parameter.
  66.         bra        pBeginUpdate            ; go to high-level stuff.
  67.  
  68.     // Next is EndUpdate, which we need to head-patch. We set up a4, call the
  69.     // high-level patch, and when it returns we go to the real routine.  Note that
  70.     // all the registers are saved, so high-level routine doesn't need to bother.
  71.  
  72. _NewEndUpdate:
  73.         dc.l    WayBadValue
  74.         movem.l    d0/d1/d2/a0/a1/a4,-(a7)    ; save registers
  75.         lea        main,a4
  76.         move.l    28(a7), -(a7)            ; pass WindowPtr that was original parameter
  77.         bsr        pEndUpdate                ; call head patch
  78.         movem.l    (a7)+,d0/d1/d2/a0/a1/a4    ; restore regs.
  79.         move.l    @_NewEndUpdate,-(a7)
  80.         rts                                ; go to original routine
  81.     }
  82. }
  83.  
  84. /*
  85.  * 14 June 1993 MCS: the technique (and code) used in pBeginUpdate is lifted
  86.  * with changes from Essential.c
  87.  */
  88. pascal void
  89. pBeginUpdate( WindowPtr wp, BEUpdateRoutine *oldBeginUpdateProc )
  90. {
  91.     long            regs[6];
  92.     GDHandle        savedevice;
  93.     CGrafPtr        saveport;
  94.     PixMapHandle    pmh;
  95.     Boolean            iscgraf, isdesktop;
  96.     Point            pt;
  97.     Rect            r, boundsr;
  98.     short            i, depth;
  99.     Str255            titleps;
  100.     unsigned char    *p;
  101. /*
  102.     StringHandle    sh;
  103. */
  104.  
  105.     asm { movem.l d0/d1/d2/a0/a1/a4,regs }    /* save the registers */
  106.     SetA4( &main ); /* set up access to our globals */
  107.     
  108.     // DebugStr( "\ppBeginUpdate calling (original) BeginUpdate" );
  109.  
  110.     oldBeginUpdateProc( wp );    /* call the real BeginUpdate */
  111.  
  112.     if ( !inited ) {
  113.         desktopsh = GetString( 10250 );    /* XXX need to ensure that we get this from Finder */
  114.         /* sh = GetString( STR_ONOFF ); */
  115.         besmooth = true; 
  116.         inited = true;
  117.     }
  118.  
  119.     if ( besmooth ) {
  120.         GetWTitle( wp, titleps );
  121.         isdesktop = false;            /* optimistic */
  122.     
  123.         if ( desktopsh != NULL ) {
  124.             LoadResource( (Handle)desktopsh );
  125.             if ( titleps[ 0 ] == **desktopsh ) {
  126.                 p = *desktopsh + 1;
  127.                 for ( i = 1; i <= titleps[ 0 ]; ++i, ++p ) {
  128.                     if ( *p != titleps[ i ] ) {
  129.                         break;
  130.                     }
  131.                 }
  132.                 isdesktop = ( i > titleps[ 0 ] );
  133.             }
  134.         }
  135.     
  136.         if ( iscgraf = ((((CWindowPtr)wp)->portVersion & 0xC000 ) == 0xC000 )) {
  137.             depth = 0;    /* let NewGWorld figure out what depth to use */
  138.         } else {
  139.             depth = 1;    /* force black and white */
  140.         }
  141.     }
  142.  
  143.     if ( besmooth && iscgraf && !isdesktop ) {
  144.         GetGWorld( &saveport, &savedevice );
  145.         SetPort( wp );
  146.  
  147.         /*
  148.          * find bounds of window in global coords
  149.          */
  150.         boundsr = wp->portRect;
  151.         pt.h = wp->portRect.left;
  152.         pt.v = wp->portRect.top;
  153.         LocalToGlobal( &pt );
  154.         OffsetRect( &boundsr, pt.h, pt.v );
  155.  
  156.         /*
  157.          * create offscreen GWorld using temporary memory if possible; otherwise fall
  158.          * back to application memory
  159.          */
  160.         if ( NewGWorld( &gwp, depth, &boundsr, NULL, NULL, useTempMem ) == noErr ||
  161.                 NewGWorld( &gwp, depth, &boundsr, NULL, NULL, 0 ) == noErr ) {
  162.             /*
  163.              * erase offscreen pixmap and cram into window record
  164.              */
  165.             SetGWorld( gwp, NULL );
  166.             EraseRect( &gwp->portRect );
  167.             SetOrigin( wp->portRect.left, wp->portRect.top );
  168.             pmh = GetGWorldPixMap( gwp );
  169.             LockPixels( pmh );
  170.             if ( iscgraf ) {
  171.                 savepmh = ((CWindowPtr)wp)->portPixMap;
  172.                 ((CWindowPtr)wp)->portPixMap = pmh;
  173.             } else {
  174. //                DebugStr( "\pb & w" );
  175.                 savebm = wp->portBits;    /* struct copy */ 
  176. //                wp->portBits.rowBytes = (*pmh)->rowBytes;
  177. //                wp->portBits.bounds = (*pmh)->bounds;
  178.                 wp->portBits.baseAddr = GetPixBaseAddr( pmh );
  179.             }
  180.         } else {
  181.             gwp = NULL;
  182.         }
  183.  
  184.         SetGWorld( saveport, savedevice );
  185.     }
  186.         
  187.     asm { movem.l regs,d0/d1/d2/a0/a1/a4 } /* restore the registers */
  188. }
  189.  
  190.  
  191. pascal void
  192. pEndUpdate( wp )
  193.     WindowPtr    wp;
  194. {
  195.     GrafPtr            saveport;
  196.     PixMapHandle    pmh;
  197.     Boolean            iscgraf;
  198.  
  199.     // DebugStr( "\ppEndUpdate" );
  200.  
  201.     if ( gwp != NULL ) {
  202.         if ( iscgraf = ((((CWindowPtr)wp)->portVersion & 0xC000 ) == 0xC000 )) {
  203.             ((CWindowPtr)wp)->portPixMap = savepmh;
  204.         } else {
  205.             // wp->portBits = savebm;    /* struct copy */ 
  206.             wp->portBits.baseAddr = savebm.baseAddr;
  207.         }
  208.         GetPort( &saveport );
  209.         SetPort( wp );
  210.         pmh = GetGWorldPixMap( gwp );
  211.  
  212.         /*
  213.          * smooth update with our friend copybits
  214.          */
  215.         CopyBits( (BitMap *)*pmh, &wp->portBits, &gwp->portRect, &wp->portRect,
  216.                 srcCopy, iscgraf ? ((CGrafPtr)wp)->visRgn : wp->visRgn );
  217.  
  218.         /*
  219.          * clean up the mess: dispose of GWorld and reset clip region and port
  220.          */
  221.         UnlockPixels( pmh );
  222.         DisposeGWorld( gwp );
  223.         gwp = NULL;
  224.  
  225.         SetPort( saveport );
  226.     }
  227. }
  228.  
  229.  
  230. //  14 June 1993 MCS: The frame of the following routine was lifted from Essential.c
  231. //
  232. //     This is the routine called by Gestalt to return the Proc Pointer.
  233. //
  234. //    OSErr gestaltSelectorProc(OSType selector,long *response);
  235. //
  236. //    Note that this is not the same tack taken by Scott & Alan!  The idea
  237. //    here is that rather than returning the address of a different routine
  238. //    which returns other results, we have only this one routine and it
  239. //    returns a multitude of different things, depending on the selector.
  240. //    So, you call Gestalt with the 'sUpd' selector to get the address of this
  241. //    routine, and then you call this routine with other selectors to get
  242. //    (or do) other things.
  243.  
  244. pascal short
  245. SmUpdateGestalt( OSType selector, long *response )
  246. {
  247.     void    *oldA4;
  248.     long    result;
  249.     short    err = noErr;
  250.     
  251.     oldA4 = SetA4( &main );
  252.  
  253.     switch( selector ) {
  254.     case sSmUpdate:
  255.         result = (long)&SmUpdateGestalt;
  256.         break;
  257.  
  258.     case sSmOn:    /* enable smooth updates */
  259.         besmooth = true;
  260.         break;
  261.  
  262.     case sSmOff:    /* disable smooth updates */
  263.         besmooth = false;
  264.         break;
  265.  
  266.     case sSmStatus:    /* return current setting */
  267.         result = ( besmooth ? 1L : 0L );
  268.         break;
  269.  
  270.     default:
  271.         err = gestaltUnknownErr;
  272.     }
  273.  
  274.     SetA4( oldA4 );
  275.  
  276.     if ( err == noErr ) {
  277.         *response = result;
  278.     }
  279.  
  280.     return( err );
  281. }
  282.